Type Level Domain Modeling
UMLなどの外部のツールを使用せずに、仕様と実装を直接管理できる
primitive typeで表現できるような概念はnewtypeなどで定義する ユビキタス言語的には、stringのような概念は無いので逐一それ用の型を用意しようという話
その組み合わせの概念は、直和や直積の形で型を定義する
code:hs
data OrderQuantity = UnitQuantity Unit
| KilogramQuantity Kilogram
現時点で不明な型がある場合
とりあえず明示的にUndefined型にしておき、わかった時点で書き換える
F#ならexn型を使用して、type Undefined = exn型を作る これで型レベルでの静的検査には通過できる
が、実装時には無理になるので、そのタイミングにでもUndefinedを別のものに替える
例えば、ShippingAddressとBillingAddressのような型が現れた時
彼が別物といえば、全く同じ構造であっても、別物として定義しておく
型定義の話では出てこないか?
関数型で定義する
code:fs
type ValidateOrder = UnvalidateOrder -> ValidatedOrder
これ簡単そうに見えて難しいよなmrsekut.icon
選ぶ動詞がかなり適切でないとミスる
右辺に来るものが「何の」状態を表しているのかを明確にわかるものにしていないといけない
出力が複数ある場合は直積、直和で表現する
入力が複数ある場合は
ORの場合は直和
ANDの場合は、
カリー化して引数の数を増やす
こうすると直積にするよりもDIしやすい
特に、入力が「本当の入力」ではなくただの依存関係である場合は、こちらのほうが良い
ただし、各値がめっちゃ密接なものの場合はRecordにしても良い
副作用を関数型で表現する
失敗の可能性がある場合はResult型を使用する
非同期処理の場合はAsync型を使用する
複合したやつはこんな感じ
code:ex.fs
type ValidateOrder =
UnvalidatedOrder -> Async<Result<ValidateOrder, ValidationError list>>
通信系の処理では、Async&Resultの組み合わせはよくあるのでエイリアスを定義しておくといい
code:fs
type ValidationResponse<'a> = Async<Result<'a, ValidationError list>>
参考